#if UNITY_EDITOR
using InternalEditor;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

namespace GameDesigner
{
    public partial class StateMachineWindow
    {
        private TwoPaneSplitView mainLayout;
        private VisualElement leftPanel;
        private VisualElement rightPanel;
        private IMGUIContainer editorToolbarUI;
        private IMGUIContainer editorUI;
        private IMGUIContainer graphToolbarUI;
        private IMGUIContainer graphUnderlayUI;
        private IMGUIContainer graphUI;
        private IMGUIContainer graphOverlayUI;
        private LayerView layerEditor;
        private bool miniTool;
        private Rect selectionRect;
        private static readonly int kDragNodesControlID = "DragNodes".GetHashCode();
        private static readonly int kDragSelectionControlID = "DragSelection".GetHashCode();

        public Rect graphViewport
        {
            get
            {
                if (graphUI == null)
                    return Rect.zero;
                Vector2 vector = graphUI.transform.matrix.inverse.MultiplyPoint(graphUI.layout.min);
                Vector2 vector2 = graphUI.transform.matrix.inverse.MultiplyPoint(graphUI.layout.max);
                return Rect.MinMaxRect(vector.x, vector.y, vector2.x, vector2.y);
            }
        }

        public void Init()
        {
            makeTransition = null;

            layerEditor = new LayerView();
            layerEditor.Init();

            rootVisualElement.AddStyleSheetPathEx("StyleSheets/Animation/AnimatorWindow.uss");
            mainLayout = new TwoPaneSplitView(0, 150f, TwoPaneSplitViewOrientation.Horizontal) { name = "MainLayout" };

            leftPanel = new VisualElement() { name = "_LeftPanel" }; //奇葩, 2022版本如果名称是LeftPanel则不能拖动
            var editorToolbar = new VisualElement { name = "EditorToolbar" }; //左边工具栏, 显示层级按钮 布局
            editorToolbarUI = new IMGUIContainer(() => OnGUIEditorToolbar(editorToolbarUI.layout)) { name = "EditorToolbarUI" }; //左边工具栏, 显示层级按钮
            editorToolbar.Add(editorToolbarUI);
            leftPanel.Add(editorToolbar);

            var editor = new VisualElement { name = "Editor" }; //左边编辑器部分 布局
            editorUI = new IMGUIContainer(() => OnGUIEditor(editorUI.layout)) { name = "EditorUI" }; //左边编辑器部分 显示层级选项
            editor.Add(editorUI);
            leftPanel.Add(editor);
            leftPanel.RegisterCallback<MouseDownEvent>((mouseDownEvent) => { }, TrickleDown.NoTrickleDown);

            mainLayout.Add(leftPanel);

            rightPanel = new VisualElement() { name = "RightPanel" };
            var graphToolbar = new VisualElement() { name = "GraphToolbar" }; //右边工具栏布局
            graphToolbarUI = new IMGUIContainer(() => DoGraphToolbar(graphToolbarUI.layout)) { name = "GraphToolbarUI" }; //右边工具栏UI显示
            graphToolbar.Add(graphToolbarUI);
            rightPanel.Add(graphToolbar);

            var graph = new VisualElementLayout //状态机视图布局
            {
                name = "Graph",
                style = { overflow = Overflow.Hidden },
                focusable = true,
                pickingMode = PickingMode.Position
            };
            var graphUnderlayGUI = new Action(() =>
            {
                if (Event.current.type == EventType.Repaint)
                    UnityEditor.Graphs.Styles.graphBackground.Draw(graphUnderlayUI.layout, false, false, false, false);
            });
            graphUnderlayUI = new IMGUIContainer(graphUnderlayGUI) //状态机视图地毯
            {
                name = "GraphUnderlayUI",
                focusable = false,
                pickingMode = PickingMode.Ignore
            };
            graph.Add(graphUnderlayUI);

            var graphGUI = new Action(() =>
            {
                DoGraph(graphViewport, graphUI.transform.scale.x);
                //HandleHotkeys(Event.current);
            });
            graphUI = new IMGUIContainer(graphGUI) //状态机视图UI
            {
                name = "GraphUI",
                style = { overflow = Overflow.Visible },
                focusable = false,
                pickingMode = PickingMode.Ignore
            };
            graphUI.transform.position = Vector3.zero;
            graphUI.transform.scale = Vector3.one;
            graphUI.style.transformOrigin = new TransformOrigin(0f, 0f, 0f);
            graph.Add(graphUI);

            var graphOverlayGUI = new Action(() =>
            {
                if (Event.current.type == EventType.Repaint && selectionRect != Rect.zero)
                {
                    UnityEditor.Graphs.Styles.selectionRect.Draw(selectionRect, false, false, false, false);
                    selectionRect = Rect.zero;
                }
            });
            graphOverlayUI = new IMGUIContainer(graphOverlayGUI) //状态机视图覆盖层
            {
                name = "GraphOverlayUI",
                focusable = false,
                pickingMode = PickingMode.Ignore
            };
            graph.Add(graphOverlayUI);

            graph.handleEventDelegate += e => //监听事件, 右键显示菜单
            {
                var imguiEvent = e.imguiEvent;
                if (imguiEvent != null)
                {
                    if (imguiEvent.type == EventType.MouseDown)
                        GUIUtility.keyboardControl = 0;
                    var mousePosition = imguiEvent.mousePosition;
                    imguiEvent.mousePosition = graphUI.WorldToLocal(imguiEvent.mousePosition);
                    graphUI.SendEventToIMGUIEx(e, true, false);
                    imguiEvent.mousePosition = mousePosition;
                    if (imguiEvent.type == EventType.Used)
                        e.StopPropagation();
                }
            };
            var zoomManipulator = new ZoomManipulator(graphUI);
            graph.AddManipulator(zoomManipulator);
            var panManipulator = new PanManipulator(graphUI);
            graph.AddManipulator(panManipulator);
            rightPanel.Add(graph);
            mainLayout.Add(rightPanel);
            mainLayout.RegisterCallback(delegate (MouseDownEvent e)
            {
                //this.editor.OnLostFocus();
                //bool flag = this.activeGraphGUI != null && e.button == 0 && this.activeGraphGUI.selection.Count == 0 && this.activeGraphGUI.edgeGUI.edgeSelection.Count == 0;
                //if (flag)
                //{
                //    this.activeGraphGUI.DoBackgroundClickAction();
                //}
            }, TrickleDown.NoTrickleDown);
            leftPanel.RegisterCallback(delegate (GeometryChangedEvent _)
            {
                if (mainLayout.fixedPane != null)
                {
                    if (mainLayout.fixedPane.layout.width < 5f)
                    {
                        mainLayout.CollapseChild(0);
                        miniTool = true;
                    }
                }
            }, TrickleDown.NoTrickleDown);
            if (miniTool)
                mainLayout.CollapseChild(0);
            rootVisualElement.Add(mainLayout);

            CenterView();
        }

        public void OnGUIEditorToolbar(Rect topToolBarRect)
        {
            GUILayout.BeginArea(topToolBarRect);
            GUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.Height(30));
            GUILayout.Space(4f);

            GUILayout.Button(Styles.layers, EditorStyles.toolbarButton);

            GUILayout.FlexibleSpace();
            if (GUILayout.Button(Styles.visibleON, Styles.invisibleButton))
            {
                mainLayout.CollapseChild(0);
                miniTool = true;
            }

            GUILayout.Space(4f);
            GUILayout.EndHorizontal();
            GUILayout.EndArea();
            if (Event.current.type != EventType.Repaint)
                return;
            DrawSeparator(topToolBarRect);
        }

        private void DrawSeparator(Rect r)
        {
            //Rect position = new Rect(r.xMax - 1f, r.yMin, 1f, r.yMax);
            //UnityEditor.Graphs.Styles.separator.Draw(position, false, false, false, false);
        }

        public void OnGUIEditor(Rect editorRect)
        {
            layerEditor.OnEvent();
            GUILayout.BeginArea(editorRect);
            GUILayout.BeginHorizontal(EditorStyles.toolbar, new GUILayoutOption[]
            {
                //GUILayout.Height(kWindowToolbarHeight)
            });
            GUILayout.Space(10f);
            GUILayout.FlexibleSpace();
            layerEditor.OnToolbarGUI();
            GUILayout.EndHorizontal();
            layerEditor.OnGUI(editorRect);
            GUILayout.EndArea();
            if (Event.current.type == EventType.Repaint)
                DrawSeparator(editorRect);
            if (Event.current.type == EventType.ContextClick && editorRect.Contains(Event.current.mousePosition))
                Event.current.Use();
        }

        private void DoGraphToolbar(Rect toolbarRect) //右边工具栏UI
        {
            GUILayout.BeginArea(toolbarRect);
            GUILayout.BeginHorizontal(EditorStyles.toolbar);
            if (miniTool)
            {
                GUILayout.Space(2f);
                if (GUILayout.Button(Styles.visibleOFF, Styles.invisibleButton))
                {
                    mainLayout.UnCollapse();
                    miniTool = false;
                }
                GUILayout.Space(5f);
            }
            for (int i = 0; i < layers.Count; ++i)
            {
                if (miniTool && i == 0)
                {
                    if (EditorGUILayout.DropdownButton(new GUIContent(layers[i].name), FocusType.Keyboard, EditorStyles.toolbarPopup))
                    {
                        //var genericMenu = new GenericMenu();
                        //for (int userData = 0; userData < 2; ++userData)
                        //    genericMenu.AddItem(new GUIContent("layer " + userData), false, new GenericMenu.MenuFunction2(SetCurrentLayer), userData);
                        //genericMenu.AddSeparator(string.Empty);
                        //genericMenu.AddItem(EditorGUIUtility.TrTextContent("Create New Layer"), false, new GenericMenu.MenuFunction(AddNewLayer));
                        //genericMenu.ShowAsContext();
                    }
                }
                else
                {
                    BreadCrumb(i, layers[i].name);
                }
            }
            GUILayout.FlexibleSpace();
            GUILayout.Space(10);
            support = EditorGUILayout.ObjectField(string.Empty, support, typeof(StateMachineView), true, GUILayout.Width(150)) as StateMachineView;
            if (GUILayout.Button("刷新脚本", EditorStyles.toolbarButton, GUILayout.Width(60)))
            {
                StateMachineViewEditor.OnScriptReload();
            }
            if (GUILayout.Button(PluginSetting.Language["reset"], EditorStyles.toolbarButton, GUILayout.Width(50)))
            {
                if (support == null)
                    return;
                CenterView();
            }
            GUILayout.EndHorizontal();
            GUILayout.EndArea();
        }

        public void CenterView()
        {
            if (support == null | graphUI == null)
                return;
            if (stateMachine.States.Length > 0)
            {
                var nodesBoundingBox = GetNodesRect();
                FrameRect(nodesBoundingBox);
            }
            else
            {
                ResetGraphView();
            }
        }

        private void FrameRect(Rect targetRect)
        {
            for (int i = 0; i < 200; i++)
            {
                if (targetRect == Rect.zero) return;
                var parent = graphUI.parent;
                var matrix = graphUI.transform.matrix;
                var contentCenter = targetRect.center;
                var viewportCenter = parent.layout.size * 0.5f;
                var scaledCenter = (Vector2)matrix.MultiplyPoint(contentCenter);
                var positionDelta = matrix.m00 * (viewportCenter - scaledCenter);
                graphUI.transform.position += (Vector3)positionDelta;
            }
        }

        private Rect GetNodesRect()
        {
            if (stateMachine.States.Length == 0)
                return Rect.zero;
            Rect bounds = stateMachine.States[0].position;
            foreach (var state in stateMachine.States)
            {
                bounds.xMin = Mathf.Min(bounds.xMin, state.position.xMin);
                bounds.yMin = Mathf.Min(bounds.yMin, state.position.yMin);
                bounds.xMax = Mathf.Max(bounds.xMax, state.position.xMax);
                bounds.yMax = Mathf.Max(bounds.yMax, state.position.yMax);
            }
            return bounds;
        }

        private void ResetGraphView()
        {
            graphUI.transform.position = Vector3.zero;
            graphUI.transform.scale = Vector3.one;
        }

        private void DoGraph(Rect gridRect, float zoomLevel)
        {
            BeginGraphGUI(gridRect, zoomLevel);
            BeginWindows();
            mousePosition = Event.current.mousePosition;
            currentType = Event.current.type;
            currentEvent = Event.current;
            if (support != null)
            {
                DrawTransitionLines();
                DrawStates();
                DragStates();
                DragSelection();
            }
            else layers.Clear();
            EndWindows();
            HandleEvents();
            HandleContextMenu();
            Repaint();
        }

        private void HandleEvents()
        {
            var current = Event.current;
            switch (current.type)
            {
                case EventType.KeyDown:
                    if (current.keyCode == KeyCode.Delete)
                    {
                        DeleteStateCallback();
                        current.Use();
                    }
                    break;
                case EventType.ValidateCommand:
                    if (current.commandName == "SoftDelete" || current.commandName == "Delete" ||
                        current.commandName == "Copy" || current.commandName == "Paste" ||
                        current.commandName == "Duplicate" || current.commandName == "SelectAll")
                        current.Use();
                    break;
                case EventType.ExecuteCommand:
                    if (current.commandName == "SoftDelete" || current.commandName == "Delete")
                    {
                        DeleteStateCallback();
                        current.Use();
                    }
                    if (current.commandName == "Copy")
                    {
                        current.Use();
                    }
                    else if (current.commandName == "Paste")
                    {
                        current.Use();
                    }
                    else if (current.commandName == "Duplicate")
                    {
                        current.Use();
                    }
                    else if (current.commandName == "SelectAll")
                    {
                        current.Use();
                    }
                    break;
            }
        }

        private void HandleContextMenu()
        {
            var current = Event.current;
            if (current.type == EventType.ContextClick)
            {
                var genericMenu = new GenericMenu();
                if (support != null)
                {
                    genericMenu.AddItem(EditorGUIUtility.TrTextContent(PluginSetting.Language["Create state"]), on: false, AddStateCallback);
                    genericMenu.AddItem(EditorGUIUtility.TrTextContent("Create Sub-State Machine"), on: false, AddStateMachineCallback);
                    genericMenu.AddItem(EditorGUIUtility.TrTextContent("创建返回状态"), false, AddBackStateCallback);
                    if (stateMachine.SelectStates.Count > 0)
                        genericMenu.AddItem(EditorGUIUtility.TrTextContent(PluginSetting.Language["Paste Selection Status"]), on: false, PasteCallback);
                    else
                        genericMenu.AddDisabledItem(EditorGUIUtility.TrTextContent(PluginSetting.Language["Paste Selection Status"]));
                }
                else
                {
                    genericMenu.AddItem(EditorGUIUtility.TrTextContent(PluginSetting.Language["Create a state machine"]), false, delegate
                    {
                        var gameObject = Selection.activeGameObject;
                        if (gameObject == null)
                        {
                            EditorUtility.DisplayDialog(PluginSetting.Language["Tips!"], PluginSetting.Language["Please select the object and click to create the state machine!"], PluginSetting.Language["yes"], PluginSetting.Language["no"]);
                            return;
                        }
                        if (!gameObject.TryGetComponent<StateManager>(out var manager))
                            manager = gameObject.AddComponent<StateManager>();
                        var support = StateMachineMono.CreateSupport();
                        manager.support = support;
                        support.transform.SetParent(manager.transform);
                        support.OnScriptReload();
                        Init(support);
                        SetDirty(support);
                    });
                }
                genericMenu.ShowAsContext();
                current.Use();
            }
        }

        private void AddBackStateCallback()
        {
            stateMachine.AddParentState("返回状态" + stateMachine.States.Length, mousePosition);
            SetDirty(support);
        }

        private void AddStateCallback()
        {
            stateMachine.AddState(PluginSetting.Language["New state"] + stateMachine.States.Length).SetNodePosition(mousePosition);
            SetDirty(support);
        }

        private void AddStateMachineCallback()
        {
            stateMachine.AddSubState("子状态机" + stateMachine.States.Length, mousePosition);
            support.OnScriptReload();
            SetDirty(support);
        }

        private void PasteCallback()
        {
            var states = new List<State>();
            var seles = stateMachine.SelectStates;

            var newState = stateMachine.CloneState(stateMachine.SelectState);
            newState.position.center = mousePosition;
            var dis = stateMachine.SelectState.position.center - mousePosition;
            states.Add(newState);

            for (int i = 1; i < stateMachine.SelectStates.Count; ++i)
            {
                newState = stateMachine.CloneState(stateMachine.States[seles[i]]);
                newState.position.position -= dis;
                states.Add(newState);
            }
            foreach (var state in states)
                foreach (var tran in state.transitions)
                    foreach (var sta in states)
                        if (tran.NextId == sta.preId)
                            tran.NextId = sta.Id;
            stateMachine.UpdateStates();
            support.OnScriptReload();
            var list = new List<int>();
            for (int i = 0; i < states.Count; ++i)
                list.Add(states[i].Id);
            stateMachine.SelectStates = list;
            SetDirty(support);
        }

        internal void ResetUI()
        {
            support.controller.selectedLayerIndex = layerEditor.selectedLayerIndex;
            support.UpdateEditStateMachine(-1);
            layers.Clear();
            layers.Add(new StateLayerEditor()
            {
                name = stateMachine.name,
                stateMachine = stateMachine,
            });
            CenterView();
        }
    }
}
#endif